package org.jflame.captcha.creator.factory;

import org.jflame.captcha.creator.CaptchaCreator;
import org.jflame.commons.config.BaseParamStrategy;
import org.jflame.commons.config.ConfigKey;
import org.jflame.commons.util.IOHelper;
import org.jflame.commons.util.StringHelper;
import org.jflame.commons.util.file.FileHelper;

import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.GraphicsEnvironment;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

@SuppressWarnings("rawtypes")
public abstract class CaptchaCreatorFactory {

    /**
     * 配置属性:验证码类型
     */
    public static final ConfigKey<String[]> KEY_TYPE = new ConfigKey<>("captcha.type", new String[] { "simple_image" });

    /**
     * 配置属性:验证码缓存类型.<br>
     * 取值:session,redis,spring,caffeine,guava
     */
    public static final ConfigKey<String> KEY_CACHE_TYPE = new ConfigKey<>("captcha.cache-type", "session");
    /**
     * 配置属性:验证码过期时间. 如果缓存到session配置无效
     */
    public static final ConfigKey<String> KEY_CACHE_TIME = new ConfigKey<>("captcha.cache-time", "300");

    private static Map<String,CaptchaCreatorFactory> creatorMap = new HashMap<>();

    /*static {
        register(new TextCreatorFactory());
        register(new SimpleImageCreatorFactory());
        register(new MathImageCreatorFactory());
        register(new WordClickCreatorFactory());
    }*/

    public static void register(CaptchaCreatorFactory creatorFactory) {
        if (creatorMap.containsKey(creatorFactory.getCaptchaType())) {
            throw new IllegalArgumentException(creatorFactory.getCaptchaType() + "同名工厂类已经存在");
        }
        creatorMap.put(creatorFactory.getCaptchaType(), creatorFactory);
    }

    /**
     * 传入验证码类型和对应属性配置构建一个该类型验证码的创建器
     * 
     * @param captchaType 验证码类型
     * @param catpchaCfg 验证码属性配置
     * @return
     */
    public static CaptchaCreator build(String captchaType, BaseParamStrategy catpchaCfg) {
        String classNamePreffix=StringHelper.underlineToCamel(captchaType,true);
        CaptchaCreatorFactory factory = creatorMap.get(captchaType);
        if (factory == null) {
            classNamePreffix+"CreatorFactory";
        }
        return factory.build(catpchaCfg);
    }

    /**
     * 从配置项中构建验证码创建器
     * 
     * @param catpchaCfg
     * @return
     */
    public abstract CaptchaCreator build(BaseParamStrategy catpchaCfg);

    /**
     * 返回要创建的验证码类型名
     * 
     * @return
     */
    // public abstract String getCaptchaType();

    protected Font loadFont(String fontNameOrFile, int fontSize) {
        if (StringHelper.isEmpty(fontNameOrFile)) {
            return null;
        }
        InputStream stream = null;
        Font font = null;
        try {
            if (fontNameOrFile.startsWith("file:")) {
                stream = new FileInputStream(fontNameOrFile.replaceFirst(fontNameOrFile, "file:")
                        .trim());
                font = createFont(stream, fontSize);
            } else if (fontNameOrFile.startsWith("classpath:")) {
                stream = FileHelper.readFileFromClassPath(fontNameOrFile.replaceFirst(fontNameOrFile, "classpath:")
                        .trim());
                font = createFont(stream, fontSize);
            } else {
                font = new Font(fontNameOrFile, Font.PLAIN, fontSize);
            }
        } catch (FontFormatException | IOException e) {
            throw new RuntimeException("字段加载异常", e);
        } finally {
            IOHelper.closeQuietly(stream);
        }
        return font;
    }

    protected Font createFont(InputStream stream, int fontSize) throws FontFormatException, IOException {
        if (stream == null) {
            return null;
        }
        Font f = Font.createFont(Font.TRUETYPE_FONT, stream);
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        ge.registerFont(f.deriveFont(fontSize));
        return f;

    }

    String keyFmt = "captcha.%s.%s";

    protected String cfgKey(String cfgKey) {
        return String.format(keyFmt, getCaptchaType(), cfgKey);
    }
}
